﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace 经典2048
{
    /// <summary>
    /// 游戏类
    /// </summary>
    public class Game
    {
        /// <summary>
        /// 地图
        /// </summary>
        public int[,] map = new int[4, 4];
        public Game()
        {
            //初始化
            Init();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public void Init()
        {
            map = new int[4, 4];
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    map[i, j] = 0;
                }
            }
            //产生一个2或4
            CreateNumber();
            //产生一个2或4
            CreateNumber();
        }

        /// <summary>
        /// 25%:4 75%:2
        /// </summary>
        /// <returns></returns>
        private int RandomNumber()
        {
            int rand = new Random().Next(1, 101);
            if (rand > 75)
            {
                return 4;
            }
            return 2;
        }

        /// <summary>
        /// 产生一个2或4并放置到未有数字的地方
        /// </summary>
        public void CreateNumber()
        {
            int index = new Random().Next(0, 16);
            Thread.Sleep(100);
            int rand = RandomNumber();
            int i = 0, j = 0;

            i = index / 4;
            j = index % 4;

            while (true)
            {
                if (map[i, j] == 0)
                {
                    map[i, j] = rand;
                    break;
                }
                j++;
                index--;
                if (j == 4)
                {
                    i++;
                    j = 0;
                    if (i == 4)
                    {
                        i = 0;
                    }
                }
            }
        }

        /// <summary>
        /// 是否可以上移
        /// </summary>
        /// <returns></returns>
        private bool CanMoveUp()
        {
            for (int j = 0; j < 4; j++)
            {
                for (int i = 3; i >= 1; i--)
                {
                    if (map[i, j] > 0)
                    {
                        for (int k = 0; k < i; k++)
                        {
                            if (map[k, i] == 0)
                            {
                                return true;
                            }
                        }
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 是否可以下移
        /// </summary>
        /// <returns></returns>
        private bool CanMoveDown()
        {
            for (int j = 0; j < 4; j++)
            {
                for (int i = 0; i < 3; i++)
                {
                    if (map[i, j] > 0)
                    {
                        for (int k = i + 1; k < 4; k++)
                        {
                            if (map[k, j] == 0)
                            {
                                return true;
                            }
                        }
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 是否可以左移
        /// </summary>
        /// <returns></returns>
        private bool CanMoveLeft()
        {
            for (int i = 0; i < 4; i++)
            {
                for (int j = 3; j >= 1; j--)
                {
                    if (map[i, j] > 0)
                    {
                        for (int k = 0; k < j; k++)
                        {
                            if (map[i, k] == 0)
                            {
                                return true;
                            }
                        }
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 是否可以右移
        /// </summary>
        /// <returns></returns>
        private bool CanMoveRight()
        {
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    if (map[i, j] > 0)
                    {
                        for (int k = j + 1; k < 4; k++)
                        {
                            if (map[i, k] == 0)
                            {
                                return true;
                            }
                        }
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 是否可以向上合并
        /// </summary>
        /// <returns></returns>
        private bool CanCombineUp()
        {
            for (int i = 1; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    if (map[i, j] != 0 && map[i - 1, j] == map[i, j])
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 是否可以向下合并
        /// </summary>
        /// <returns></returns>
        private bool CanCombineDown()
        {
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    if (map[i, j] != 0 && map[i + 1, j] == map[i, j])
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 是否可以向左合并
        /// </summary>
        /// <returns></returns>
        private bool CanCombineLeft()
        {
            for (int i = 0; i < 4; i++)
            {
                for (int j = 1; j < 4; j++)
                {
                    if (map[i, j] != 0 && map[i, j - 1] == map[i, j])
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 是否可以向右合并
        /// </summary>
        /// <returns></returns>
        private bool CanCombineRight()
        {
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    if (map[i, j] != 0 && map[i, j + 1] == map[i, j])
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 是否可以移动
        /// </summary>
        /// <returns></returns>
        private bool CanMove()
        {
            return CanMoveDown() || CanMoveLeft() || CanMoveRight() || CanMoveUp();
        }

        /// <summary>
        /// 是否可以合并
        /// </summary>
        /// <returns></returns>
        private bool CanCombine()
        {
            return CanCombineDown() || CanCombineLeft() || CanCombineRight() || CanCombineUp();
        }

        /// <summary>
        /// 是否已经结束
        /// </summary>
        /// <returns></returns>
        public bool IsOver()
        {
            return !(CanMove() || CanCombine());
        }

        /// <summary>
        /// 是否获胜
        /// </summary>
        /// <returns></returns>
        public bool Success()
        {
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    if (map[i, j] >= 2048)
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 是否可以执行某操作
        /// </summary>
        /// <returns></returns>
        private bool CanTurn(TurnType type)
        {
            switch (type)
            {
                case TurnType.上:
                    return CanMoveUp() || CanCombineUp();
                case TurnType.下:
                    return CanMoveDown() || CanCombineDown();
                case TurnType.左:
                    return CanMoveLeft() || CanCombineLeft();
                case TurnType.右:
                    return CanMoveRight() || CanCombineRight();
                default:
                    return false;
            }
        }

        /// <summary>
        /// 上移
        /// </summary>
        private void MoveUp()
        {
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    if (map[i, j] == 0)
                    {
                        int k = i + 1;
                        while (k < 4 && map[k, j] == 0)
                        {
                            k++;
                        }
                        if (k == 4)
                        {
                            continue;
                        }
                        for (int l = i; l < 4 && k < 4; l++, k++)
                        {
                            map[l, j] = map[k, j];
                            map[k, j] = 0;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 左移
        /// </summary>
        private void MoveLeft()
        {
            for (int j = 0; j < 3; j++)
            {
                for (int i = 0; i < 4; i++)
                {
                    if (map[i, j] == 0)
                    {
                        int k = j + 1;
                        while (k < 4 && map[i, k] == 0)
                        {
                            k++;
                        }
                        if (k == 4)
                        {
                            continue;
                        }
                        for (int l = j; l < 4 && k < 4; l++, k++)
                        {
                            map[i, l] = map[i, k];
                            map[i, k] = 0;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 下移
        /// </summary>
        private void MoveDown()
        {
            for (int i = 3; i >= 1; i--)
            {
                for (int j = 0; j < 4; j++)
                {
                    if (map[i, j] == 0)
                    {
                        int k = i - 1;
                        while (k >= 0 && map[k, j] == 0)
                        {
                            k--;
                        }
                        if (k < 0)
                        {
                            continue;
                        }
                        for (int l = i; l >= 0 && k >= 0; l--, k--)
                        {
                            map[l, j] = map[k, j];
                            map[k, j] = 0;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 右移
        /// </summary>
        private void MoveRight()
        {
            for (int j = 3; j >= 1; j--)
            {
                for (int i = 0; i < 4; i++)
                {
                    if (map[i, j] == 0)
                    {
                        int k = j - 1;
                        while (k >= 0 && map[i, k] == 0)
                        {
                            k--;
                        }
                        if (k < 0)
                        {
                            continue;
                        }
                        for (int l = j; l >= 0 && k >= 0; l--, k--)
                        {
                            map[i, l] = map[i, k];
                            map[i, k] = 0;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 上合
        /// </summary>
        private void CombineUp()
        {
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    if (map[i, j] == 0)
                    {
                        continue;
                    }
                    if (map[i, j] == map[i + 1, j])
                    {
                        map[i, j] += map[i + 1, j];
                        map[i + 1, j] = 0;
                    }
                }
            }
        }

        /// <summary>
        /// 下合
        /// </summary>
        private void CombineDown()
        {
            for (int i = 3; i >= 1; i--)
            {
                for (int j = 0; j < 4; j++)
                {
                    if (map[i, j] == 0)
                    {
                        continue;
                    }
                    if (map[i, j] == map[i - 1, j])
                    {
                        map[i, j] += map[i - 1, j];
                        map[i - 1, j] = 0;
                    }
                }
            }
        }

        /// <summary>
        /// 左合
        /// </summary>
        private void CombineLeft()
        {
            for(int i = 0; i < 4; i++)
            {
                for(int j = 0; j < 3; j++)
                {
                    if (map[i, j] == 0)
                    {
                        continue;
                    }
                    if (map[i, j] == map[i, j + 1])
                    {
                        map[i, j] += map[i, j + 1];
                        map[i, j + 1] = 0;
                    }
                }
            }
        }

        /// <summary>
        /// 右合
        /// </summary>
        private void CombineRight()
        {
            for(int i = 0; i < 4; i++)
            {
                for(int j = 3; j >= 1; j--)
                {
                    if (map[i, j] == 0)
                    {
                        continue;
                    }
                    if (map[i, j] == map[i, j - 1])
                    {
                        map[i, j] += map[i, j - 1];
                        map[i, j - 1] = 0;
                    }
                }
            }
        }
   
        /// <summary>
        /// 执行用户的操作
        /// </summary>
        /// <param name="type"></param>
        public void Turn(TurnType type)
        {
            //可以进行此操作的话
            //便执行操作，并生成一个新的数字
            if (CanTurn(type))
            {
                switch (type)
                {
                    case TurnType.上:
                        MoveUp();
                        CombineUp();
                        MoveUp();
                        break;
                    case TurnType.下:
                        MoveDown();
                        CombineDown();
                        MoveDown();
                        break;
                    case TurnType.左:
                        MoveLeft();
                        CombineLeft();
                        MoveLeft();
                        break;
                    case TurnType.右:
                        MoveRight();
                        CombineRight();
                        MoveRight();
                        break;
                }
                CreateNumber();
            }
        }
    }

    /// <summary>
    /// 方向枚举
    /// </summary>
    public enum TurnType
    {
        上,
        下,
        左,
        右
    }
}
